package com.adopapa.ethexplorer.contoller;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Base64;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.ECKeyPair;
import org.web3j.utils.Convert;

import com.adopapa.ethexplorer.domain.UserInfo;
import com.adopapa.ethexplorer.domain.UserInfo.UserType;
import com.adopapa.ethexplorer.service.ChaindataService;
import com.adopapa.ethexplorer.service.UserInfoService;
import com.adopapa.ethexplorer.service.WalletManager;
import com.adopapa.ethexplorer.utils.Tools;

import reactor.core.publisher.Mono;

@RestController
@RequestMapping("/api/v1/account")
public class AccountController extends BaseController {

	@Autowired
	private ChaindataService chaindataService;
	@Autowired
	private UserInfoService userInfoService;

	@PostMapping(path = "/transfer", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
	public Mono<Map<String, Object>> transfer(@RequestHeader String authorization,
			@RequestBody Map<String, Object> params) {

		String from = getMapValue(params, "from", String.class);
		String to = getMapValue(params, "to", String.class);
		Double val = getMapValue(params, "value", Double.class);
		String data = getMapValue(params, "note", String.class);

		if (Tools.empty(to) || Tools.empty(val)) {
			throw new RuntimeException("from, to or value can not empty");
		}

		UserInfo userInfo = getUserInfo(authorization);

		UserInfo fromUser = userInfo;
		if (!Tools.empty(from)) {
			fromUser = userInfoService.getUserInfoByAddress(from);
		}
		if (userInfo.getUserType() != UserType.SUPERADMIN) {
			if (Tools.empty(fromUser) || Tools.empty(fromUser.getWalletInfo())) {
				throw new RuntimeException("请确定钱包地址是否存在");
			}
		}

		BigInteger value = Convert.toWei(BigDecimal.valueOf(val), Convert.Unit.ETHER).toBigInteger();

		String privateKey = "00be6b6223868e4ca31bf986fac76e9190fdcfa78bc432647e51cb43599628def7";
		try {

			if (!Tools.empty(fromUser)) {
				String password = new String(Base64.getDecoder().decode(fromUser.getWalletInfo().getPassword()));
				privateKey = WalletManager.decryptWallet(fromUser.getWalletInfo().getKeystore(), password);
			}

		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}

		ECKeyPair ecKeyPair = ECKeyPair.create(new BigInteger(privateKey, 16));
		Credentials credentials = Credentials.create(ecKeyPair);

		if (Tools.empty(data)) {
			data = "";
		}

		try {
			String txHash = chaindataService.transfer(credentials, to, value, data);
			return Mono.just(ok(txHash));

		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}

	}

	@GetMapping(path = "/balance/{address}", produces = MediaType.APPLICATION_JSON_VALUE)
	public Mono<Map<String, Object>> getBalance(@PathVariable String address) {
		BigInteger balance = chaindataService.getBalance(address);
		return Mono.just(ok(balance));
	}

	@PostMapping(path = "/wallet", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
	public Mono<Map<String, Object>> createWallet(@RequestBody Map<String, String> params) {
		String password = params.get("password");
		if (Tools.empty(password)) {
			return Mono.just(other("password is empty"));
		}
		try {
			Map<String, String> wallet = WalletManager.createStandardWallet(password);
			return Mono.just(ok(wallet));
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
	}

}
